package com.chen.q2.snowflakes;

import java.util.stream.IntStream;

public class IdWorker {
    //下面两个每个5位，加起来就是10位的工作机器id
    private long workerId;//工作id
    private long datacenterId;//数据中心id
    //12位序列号
    private long sequence;

    public IdWorker(long workerId, long datacenterId, long sequence){
        //sanity check for worker
        if (workerId > maxWorkerId || workerId < 0){
            throw new IllegalArgumentException(
                    String.format("worker id can't be greater than %d or less than 0",maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0){
            throw new IllegalArgumentException(
                    String.format("datacenter id can't be greater than %d or less than 0",maxDatacenterId));
        }
        System.out.printf("worker starting.timestamp left %d,datacenter id bits %d,worker id bits %d,sequence bits %d, worker id %d",
                timestampLeftShift,datacenterIdBits,workerIdBits,sequenceBits,workerId);
        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.sequence = sequence;
    }

    //初始时间戳
    private long twepoch = 1631779819505L;
    //长度为5位
    private long workerIdBits = 5L;
    private long datacenterIdBits = 5L;

    //最大值
    private long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    //序列号长度
    private long sequenceBits = 12L;
    //序列号最大值
    private long sequenceMask = -1L ^ (-1L << sequenceBits);

    //工作id需要左移的位数，12位
    private long workerIdShift = sequenceBits;
    //数据id需要左移的位数，12 + 5 = 17位
    private long datacenterIdShift = sequenceBits + workerIdBits;
    //时间戳需要左移的位数 12+5+5=22位
    private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits ;

    //上次时间戳，初始值为负数
    private long lastTimestamp = -1L;

    public long getWorkerId(){
        return workerId;
    }
    public long getDatacenterId(){
        return datacenterId;
    }
    public long getTimestamp(){
        return System.currentTimeMillis();
    }

    //下一个ID生成算法
    public synchronized long nextId(){
        long timestamp = System.currentTimeMillis();

        //获取当前时间戳如果小于上次时间戳，则表示时间戳获取出现异常
        if (timestamp < lastTimestamp){
            System.err.printf("clock is moving backwards. Rejecting requests until %d.",lastTimestamp);
            throw new RuntimeException(String.format("Clock move backwards.Refusing to generate id for %d milliseconds",
                    lastTimestamp - timestamp));
        }

        //获取时间戳如果等于上次时间戳(同一毫秒内)，则在序列号加1，否则序列号为0，从0开始
        if (lastTimestamp == timestamp){
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0){
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        //刷新上次时间戳
        lastTimestamp = timestamp;
        //返回结果
        return (timestamp - twepoch) << timestampLeftShift |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    //获取时间戳，与上次时间比较
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp){
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    public static void main(String[] args) {
        IdWorker idWorker = new IdWorker(1,1,1);
        new Thread(()->{
            IntStream.range(0,30).forEach(x->{
                System.out.println(idWorker.nextId());
            });
        }).start();
        new Thread(()->{
            IntStream.range(0,30).forEach(x->{
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(idWorker.nextId());
            });
        }).start();

    }
}
